package com.dong.thread.juc;

import java.util.Arrays;
import java.util.concurrent.TimeUnit;

/**
 * 生产者消费者问题
 * 写一个固定容量同步容器，拥有put和get方法，以及getCount方法，能够支持2个生产者线程以及10个消费者线程的阻塞调用
 *
 * synchronized + wait/notifyAll实现
 *
 * @author by jiweidong on 2021/11/28.
 */
public class T10_Interview_03_SyncWaitNotify {

    private static final int MAX_SIZE = 10;

    private final Object[] arr = new Object[MAX_SIZE];
    private int count = 0;

    public synchronized void put(Object o) {
        while (count >= MAX_SIZE) { //想想为什么用while而不是用if？
            try {
                System.out.println("producer put wait" + o + ", count =" + count);
                this.wait(); //effective java
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
        arr[count] = o;
        count++;
//        System.out.println(Arrays.toString(arr));
        this.notifyAll();
    }

    public synchronized Object get() {
        while (count <= 0) {
            try {
                System.out.println("consumer get wait" + ", count =" + count);
                this.wait();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
        count--;
        Object result = arr[count];
//        System.out.println(Arrays.toString(arr));
        this.notifyAll();
        return result;
    }

    public int getCount() {
        return count;
    }

    public static void main(String[] args) {
        T10_Interview_03_SyncWaitNotify container = new T10_Interview_03_SyncWaitNotify();

        // 两个生成者
        for (int i = 0; i < 2; i++) {
            new Thread(() -> {
                while (true) {
                    int o = (int) (Math.random() * 10);
                    container.put(o);
                    System.out.println("producer put " + o + ", size =" + container.getCount());
                    try {
                        TimeUnit.MILLISECONDS.sleep(100);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            }).start();
        }

        // 10个消费者
        for (int i = 0; i < 10; i++) {
            new Thread(() -> {
                while (true) {
                    Object o = container.get();
                    System.out.println("consumer get " + o + ", size =" + container.getCount());
                    try {
                        TimeUnit.MILLISECONDS.sleep(1000);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            }).start();
        }
    }


}
